﻿using System;
using HK.Core.Common.Data;
using HK.Core.Common.Protocol;
using HK.Core.Common.Protocol.Data;
using HK.Core.Extend;
using HK.Core.GUIEx.Protocol.Attribute;
using HK.Core.Serializable.Attribute;
using HK.Core.Serializable.Usage;
using HK.Core.Settings.Protocol;
using HK.Core.Utils;
using UnityEngine;

namespace HK.Core.Settings.Data
{
    /// <summary>
    /// 服务器设定数据
    /// </summary>
    [Serializable, ListElement("服务器", "serverId")]
    public class ServerSettingsData : JsonData<ServerSettingsData>, IServerSettingsData, IEquatable<ServerSettingsData>
    {
        [SerializeField, GenericField("Id")]
        private string serverId = null;
        /// <summary>
        /// 服务器Id
        /// <para>* 唯一标识Id</para>
        /// </summary>
        public string ServerId 
        {
            get => serverId;
            private set => serverId = value;
        }
        
        /// <summary>
        /// 唯一标识Element的Key
        /// </summary>
        public string Key => serverId;

        [SerializeField, GenericField("类型")]
        private ServerType type = ServerType.Dev;
        /// <summary>
        /// 服务器类型
        /// </summary>
        public ServerType Type 
        {
            get => type;
            private set => type = value;
        }
        
        [SerializeField, GenericField("地址")]
        private string address = null;
        /// <summary>
        /// 地址
        /// </summary>
        public string Address 
        {
            get => address;
            private set => address = value;
        }

        [SerializeField, GenericField("端口")]
        private int port = 0;
        /// <summary>
        /// 端口号
        /// </summary>
        public int Port 
        {
            get => port;
            private set => port = value;
        }
        
        [SerializeField, GenericField("登录端口")]
        private int loginPort = 0;
        /// <summary>
        /// 登录端口
        /// </summary>
        public int LoginPort 
        {
            get => loginPort;
            private set => loginPort = value;
        }

        /// <summary>
        /// 有效标志位
        /// </summary>
        public override bool Valid => !string.IsNullOrEmpty(serverId) && !string.IsNullOrEmpty(address) && 0 < port && 0 < loginPort;

#region Connect
        
        [SerializeField, GenericField("链接", null, "若为true，则代表与当前服务器链接成功，同意之间只能有一个服务器被链接。", (int)GUIOperateOptions.ReadOnlyGenericField)]
        private bool connected = false;
        /// <summary>
        /// 已链接
        /// </summary>
        public bool Connected 
        {
            get => connected;
            private set => connected = value;
        }
        
        /// <summary>
        /// 链接
        /// </summary>
        public void Connect() => connected = true;

        /// <summary>
        /// 断开链接
        /// </summary>
        public void Disconnect() => connected = false;

#endregion

#region Equals

        /// <summary>
        /// 比较
        /// </summary>
        /// <param name="iSettings"></param>
        /// <returns></returns>
        public bool Equals(ServerSettingsData iSettings)
        {
            if (null == iSettings || !iSettings.Valid) return false;

            if (UtilsString.Diff(serverId, iSettings.ServerId)) return false;
            if (type != iSettings.Type) return false;
            if (UtilsString.Diff(address, iSettings.Address)) return false;
            if (port != iSettings.port) return false;
            if (loginPort != iSettings.LoginPort) return false;
            return true;
        }

#endregion

        /// <summary>
        /// 应用数据
        /// </summary>
        /// <param name="iData">数据</param>
        /// <param name="iImport">导入标志位(true:从相应的*.json文件导入; false:反之;)</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public override bool ApplyData(IJsonData iData, bool iImport = false)
        {
            if (null == iData || !iData.Valid) return false;

            var dirty = base.ApplyData(iData, iImport);
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            if (iData is IServerSettingsData server)
            {
                serverId = UpdateValue(serverId, server.ServerId, iImport);
                type = UpdateValue(type, Type, iImport);
                address = UpdateValue(address, Address, iImport);
                port = UpdateValue(port, server.Port, iImport);
                loginPort = UpdateValue(loginPort, server.LoginPort, iImport);
                connected = UpdateValue(connected, server.Connected, iImport);
            }

            return Dirty;
        }
        
        /// <summary>
        /// 更新值
        /// </summary>
        /// <param name="iCurValue">当前值</param>
        /// <param name="iDstValue">目标值</param>
        /// <param name="iImport">导入标志位</param>
        /// <returns>可以更新的值</returns>
        protected ServerType UpdateValue(ServerType iCurValue, ServerType iDstValue, bool iImport)
        {
            var dirty = iCurValue != iDstValue;
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            return dirty ? iDstValue : iCurValue;
        }

        /// <summary>
        /// 清空
        /// </summary>
        public override void Clear()
        {
            base.Clear();
            
            serverId = null;
            type = ServerType.Dev;
            address = null;
            port = 0;
            loginPort = 0;
            connected = false;
        }
    }

    /// <summary>
    /// 服务器列表
    /// </summary>
    /// <typeparam name="TServers">服务器列表类型</typeparam>
    /// <typeparam name="TServer">服务器类型</typeparam>
    [Serializable]
    public abstract class ServersSettingsData<TServers, TServer> : ListJsonData<TServers, TServer>, IServersSettingsData<TServer>
        where TServers : JsonData, IServersSettingsData<TServer>
        where TServer : JsonData, IServerSettingsData, IEquatable<TServer>
    {
        /// <summary>
        /// 当前服务器
        /// <para>* 既当前连接中的服务器</para>
        /// </summary>
        public TServer CurServer
        {
            get
            {
                var count = Count;
                if (0 >= count) return null;

                TServer server = null;
                for (var idx = 0; idx < count; ++idx)
                {
                    var loop = List[idx];
                    if(null == loop || !loop.Valid || !loop.Connected) continue;

                    server = loop;
                    break;
                }
                return server;
            }
        }
        
        /// <summary>
        /// 切换服务器
        /// </summary>
        /// <param name="iServerId">服务器Id</param>
        /// <returns>true:切换失败; false:切换成功;</returns>
        public bool SwitchServer(string iServerId)
        {
            if (string.IsNullOrEmpty(iServerId))
            {
                this.Error("MarkConnect():The server id is null or empty!");
                return false;
            }
            
            var count = Count;
            if (0 >= count)
            {
                this.Error("MarkConnect():There is no server exist!");
                return false;
            }

            var flg = false;
            for (var idx = 0; idx < count; ++idx)
            {
                var loop = List[idx];
                if(null == loop || !loop.Valid || !loop.Connected) continue;

                var connected = iServerId.Equals(loop.ServerId);
                if (connected)
                {
                    loop.Connect();
                    flg = true;
                }
                else
                {
                    loop.Disconnect();
                }
            }

            if (!flg)
            {
                this.Error("MarkConnect():There is no server exist!(ServerId:{0})", iServerId);
            }

            return flg;
        }
    }

    /// <summary>
    /// 服务器列表
    /// </summary>
    [Serializable]
    public sealed class ServersSettingsData : ServersSettingsData<ServersSettingsData, ServerSettingsData>, IServersSettingsData
    {

#region Create

        /// <summary>
        /// 创建服务器列表
        /// </summary>
        /// <returns>服务器列表</returns>
        public static ServersSettingsData Create() => new ServersSettingsData();

#endregion
        
        /// <summary>
        /// 保护构造函数
        /// </summary>
        private ServersSettingsData() {}
    }
}